﻿using System;
using System.Globalization;
using System.IO;
using System.Linq;
using System.Xml;
using Microsoft.Build.Framework;
using Microsoft.Build.Utilities;
using SkiaSharp;

namespace Microsoft.Maui.Resizetizer
{
	/// <summary>
	/// Generates files relating to the Android splash screen:
	///  - Resources/values/maui_colors.xml
	///  - Resources/drawable/maui_splash_image.xml
	///  - Resources/drawable-v31/maui_splash_image.xml
	///  - Resources/[drawable]/[splash].png
	/// </summary>
	public class GenerateSplashAndroidResources : Task, ILogger
	{
		[Required]
		public string IntermediateOutputPath { get; set; }

		[Required]
		public ITaskItem[] MauiSplashScreen { get; set; }

		public string InputsFile { get; set; }

		public override bool Execute()
		{
			Log.LogMessage(MessageImportance.Low, $"Splash Screen: Intermediate Path " + IntermediateOutputPath);

			var splash = MauiSplashScreen?.FirstOrDefault();
			if (splash is null)
			{
				Log.LogMessage(MessageImportance.Low, $"Splash Screen: No images found.");
				return true;
			}

			try
			{
				var info = ResizeImageInfo.Parse(splash);

				var resizer = new Resizer(info, IntermediateOutputPath, this);

				WriteImages(resizer);
				WriteColors(resizer);
				WriteDrawable(resizer);
				WriteDrawable_v31(resizer);

				return !Log.HasLoggedErrors;
			}
			catch (Exception ex)
			{
				Log.LogError(null, "MAUI0000", null, null, 0, 0, 0, 0, ex.ToString());
				return false;
			}
		}

		static readonly XmlWriterSettings Settings = new XmlWriterSettings { Indent = true };
		const string Namespace = "http://schemas.android.com/apk/res/android";
		const string Comment = "This file was auto-generated by .NET MAUI.";
		const float PreferredImageSize = 108f;

		private void WriteImages(Resizer resizer)
		{
			if (resizer.Info.Resize)
			{
				foreach (var dpi in DpiPath.Android.Image)
				{
					Log.LogMessage(MessageImportance.Low, $"Splash Screen Resize: " + dpi);
					resizer.Resize(dpi, InputsFile);
				}
			}
			else
			{
				var dpi = DpiPath.Android.Original;

				Log.LogMessage(MessageImportance.Low, $"Splash Screen Copy: " + dpi);
				resizer.CopyFile(dpi, InputsFile);
			}
		}

		void WriteColors(Resizer resizer)
		{
			var dir = Path.Combine(IntermediateOutputPath, "values");
			Directory.CreateDirectory(dir);

			var colorsFile = Path.Combine(dir, "maui_colors.xml");

			Log.LogMessage(MessageImportance.Low, $"Splash Screen Colors: " + colorsFile);

			using var writer = XmlWriter.Create(colorsFile, Settings);
			writer.WriteComment(Comment);
			writer.WriteStartElement("resources");

			if (resizer.Info.Color is not null)
			{
				writer.WriteStartElement("color");
				writer.WriteAttributeString("name", "maui_splash_color");
				writer.WriteString(resizer.Info.Color.ToString());
				writer.WriteEndElement();
			}

			writer.WriteEndDocument();
		}

		void WriteDrawable(Resizer resizer)
		{
			var dir = Path.Combine(IntermediateOutputPath, "drawable");
			Directory.CreateDirectory(dir);

			var drawableFile = Path.Combine(dir, "maui_splash_image.xml");

			Log.LogMessage(MessageImportance.Low, $"Splash Screen Drawable: " + drawableFile);

			using var writer = XmlWriter.Create(drawableFile, Settings);
			writer.WriteComment(Comment);
			writer.WriteStartElement("layer-list");
			writer.WriteAttributeString("xmlns", "android", ns: null, value: Namespace);

			writer.WriteStartElement("item");

			writer.WriteStartElement("bitmap");
			writer.WriteAttributeString("android", "gravity", Namespace, "center");
			writer.WriteAttributeString("android", "src", Namespace, "@drawable/" + resizer.Info.OutputName);
			writer.WriteAttributeString("android", "mipMap", Namespace, "true");

			writer.WriteEndDocument();
		}

		void WriteDrawable_v31(Resizer resizer)
		{
			var size = CalculateScaledSize(resizer);

			var dir = Path.Combine(IntermediateOutputPath, "drawable-v31");
			Directory.CreateDirectory(dir);

			var drawableFile = Path.Combine(dir, "maui_splash_image.xml");

			Log.LogMessage(MessageImportance.Low, $"Splash Screen Drawable (v31): " + drawableFile);

			using var writer = XmlWriter.Create(drawableFile, Settings);
			writer.WriteComment(Comment);
			writer.WriteStartElement("layer-list");
			writer.WriteAttributeString("xmlns", "android", ns: null, value: Namespace);

			writer.WriteStartElement("item");
			writer.WriteAttributeString("android", "width", Namespace, size.Width.ToString("0", CultureInfo.InvariantCulture) + "dp");
			writer.WriteAttributeString("android", "height", Namespace, size.Height.ToString("0", CultureInfo.InvariantCulture) + "dp");
			writer.WriteAttributeString("android", "gravity", Namespace, "center");

			writer.WriteStartElement("bitmap");
			writer.WriteAttributeString("android", "gravity", Namespace, "fill");
			writer.WriteAttributeString("android", "src", Namespace, "@drawable/" + resizer.Info.OutputName);
			writer.WriteAttributeString("android", "mipMap", Namespace, "true");

			writer.WriteEndDocument();
		}

		void ILogger.Log(string message)
		{
			Log?.LogMessage(message);
		}

		static SKSize CalculateScaledSize(Resizer resizer)
		{
			var size = resizer.BaseSize ?? resizer.GetOriginalSize();

			var width = PreferredImageSize;
			var height = PreferredImageSize;

			if (size.Width > size.Height)
				height = size.Height / size.Width * width;
			else
				width = size.Width / size.Height * height;

			return new SKSize(width, height);
		}
	}
}
